#include <cmath>

template <typename DocumentType>
class TfIdfCalculator {
	// the caller already knows the number of occurences of a word in a doc
	// and the documents corresponding to a word.
	
	size_t numberOfWords;

	typedef std::map<std::string, size_t> wordsToOccurencesType;
	/** words->numberOfOccurences **/
	wordsToOccurencesType wordsNumber;

	typedef std::map<DocumentType*, size_t> documentToNumberWordsType;
	/** documents->numberOfWords **/
	documentToNumberWordsType documentSizes;

public:
	/**
	 * add a word to the corpus, updating the wordsNumber map.
	 */
	void addWord(DocumentType* doc, std::string const& word) {
		wordsToOccurencesType::iterator witer = wordsNumber.find(word);
		
		// if we didn't find the word (we reached the end of the iterator),
		// then the word is only present once in the corpus
		if (witer == wordsNumber.end())
			wordsNumber[word] = 1;
		else
		// else, it means that the word already appeared in the corpus before
			witer->second++;
		
		typename documentToNumberWordsType::iterator diter;
		diter = documentSizes.find(doc);

        // if we didn't find the doc in the map documentSizes, we consider that
        // the doc "doc" is present once
		if (diter == documentSizes.end())
			documentSizes[doc] = 1;
		else
			diter->second++;
		// anyway, we increment the number of words of the corpus
		numberOfWords++;
	}


	/**
	 * get the number of time a word appear in the corpus
	 * @param word the word to get the number of occurences 
	 * @return the number of time the given word appear in the corpus
	**/
	size_t getOccurences(std::string word)
	{ return (wordsNumber.find(word) == wordsNumber.end() )? 0:wordsNumber[word];}


	/** 
	 * get the number of different words that appears in the corpus
	 * @return the number of different words that appears in the corpus (two time the same word count as 1
	**/
	size_t getNumberOfDifferentWords()
	{return this->wordsNumber.size();}


	/** 
	 * get the number of different documents that appears in the corpus
	 * @return the number of different documents that appears in the corpus
	**/
	size_t getNumberOfDifferentDocuments()
	{return this->documentSizes.size();}

	/**	
	 * get the total number of word in the document
	 * @return the number of word in the document (two time the same word count as 2)
	**/
	size_t getNumberOfWordsInDoc(DocumentType* doc)
	{ return (documentSizes.find(doc) == documentSizes.end() )? 0:documentSizes[doc];}

	/**
	 * @param wordCount the number of occurence in the document
	 * @param document the document where the word is 
	 * @return tf of the word in the document
	**/
	double tf(size_t wordCount, DocumentType* doc) {
		return wordCount / double(getNumberOfWordsInDoc(doc));
	}

	/**
	 * @param documentsHavingWord the number of document having the word.
	 * @return idf of the word
	**/
	double idf(size_t documentsHavingWord) {
		return std::log(getNumberOfDifferentDocuments() /
				double(documentsHavingWord));
	}
	// la fleme de faire la fonction tfidf qui sera ptet pas utilisée.
};
